"""
WEEKDAY

Calculates which weekday an entered date is.

Also estimates how long a person has done certain activities, if they
entered their birthday.

Also calculates the year of retirement, assuming retiring at age 65.

Ported by Dave LeCompte.
"""

import datetime
from typing import Tuple

GET_TODAY_FROM_SYSTEM = True


def get_date_from_user(prompt: str) -> Tuple[int, int, int]:
    while True:
        print(prompt)
        date_str = input()
        try:
            month_num, day_num, year_num = (int(x) for x in date_str.split(","))
            return month_num, day_num, year_num
        except Exception:
            print("I COULDN'T UNDERSTAND THAT. TRY AGAIN.")


def get_date_from_system() -> Tuple[int, int, int]:
    dt = datetime.datetime.now()
    return dt.month, dt.day, dt.year


def get_day_of_week(weekday_index, day) -> str:
    if weekday_index == 6 and day == 13:
        return "FRIDAY THE THIRTEENTH---BEWARE!"
    day_names = {
        1: "SUNDAY",
        2: "MONDAY",
        3: "TUESDAY",
        4: "WEDNESDAY",
        5: "THURSDAY",
        6: "FRIDAY",
        7: "SATURDAY",
    }

    return day_names[weekday_index]


def previous_day(b) -> int:
    if b == 0:
        b = 6
    return b - 1


def is_leap_year(year: int) -> bool:
    if (year % 4) != 0:
        return False
    return True if (year % 100) != 0 else year % 400 == 0


def adjust_day_for_leap_year(b, year):
    if is_leap_year(year):
        b = previous_day(b)
    return b


def adjust_weekday(b, month, year):
    if month <= 2:
        b = adjust_day_for_leap_year(b, year)
    if b == 0:
        b = 7
    return b


def calc_day_value(year, month, day):
    return (year * 12 + month) * 31 + day


def deduct_time(frac, days, years_remain, months_remain, days_remain):
    # CALCULATE TIME IN YEARS, MONTHS, AND DAYS
    days_available = int(frac * days)
    years_used = days_available // 365
    days_available -= years_used * 365
    months_used = days_available // 30
    days_used = days_available - (months_used * 30)
    years_remain = years_remain - years_used
    months_remain = months_remain - months_used
    days_remain = days_remain - days_used

    while days_remain < 0:
        days_remain += 30
        months_remain -= 1

    while months_remain < 0 and years_remain > 0:
        months_remain += 12
        years_remain -= 1
    return years_remain, months_remain, days_remain, years_used, months_used, days_used


def time_report(msg, years, months, days):
    leading_spaces = 23 - len(msg)
    print(" " * leading_spaces + f"{msg}\t{years}\t{months}\t{days}")


def make_occupation_label(years):
    if years <= 3:
        return "PLAYED"
    elif years <= 9:
        return "PLAYED/STUDIED"
    else:
        return "WORKED/PLAYED"


def calculate_day_of_week(year, month, day):
    # Initial values for months
    month_table = [0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5]

    i1 = int((year - 1500) / 100)
    a = i1 * 5 + (i1 + 3) / 4
    i2 = int(a - int(a / 7) * 7)
    y2 = int(year / 100)
    y3 = int(year - y2 * 100)
    a = y3 / 4 + y3 + day + month_table[month - 1] + i2
    b = int(a - int(a / 7) * 7) + 1
    b = adjust_weekday(b, month, year)

    return b


def end() -> None:
    for _ in range(5):
        print()


def main() -> None:
    print(" " * 32 + "WEEKDAY")
    print(" " * 15 + "CREATIVE COMPUTING  MORRISTOWN, NEW JERSEY\n\n\n")
    print("WEEKDAY IS A COMPUTER DEMONSTRATION THAT")
    print("GIVES FACTS ABOUT A DATE OF INTEREST TO YOU.")
    print()

    if GET_TODAY_FROM_SYSTEM:
        month_today, day_today, year_today = get_date_from_system()
    else:
        month_today, day_today, year_today = get_date_from_user(
            "ENTER TODAY'S DATE IN THE FORM: 3,24,1979"
        )

    # This program determines the day of the week
    # for a date after 1582

    print()

    month, day, year = get_date_from_user(
        "ENTER DAY OF BIRTH (OR OTHER DAY OF INTEREST) (like MM,DD,YYYY)"
    )

    print()

    # Test for date before current calendar
    if year < 1582:
        print("NOT PREPARED TO GIVE DAY OF WEEK PRIOR TO MDLXXXII.")
        end()
        return

    b = calculate_day_of_week(year, month, day)

    today_day_value = calc_day_value(year_today, month_today, day_today)
    target_day_value = calc_day_value(year, month, day)

    is_today = False

    if today_day_value < target_day_value:
        label = "WILL BE A"
    elif today_day_value == target_day_value:
        label = "IS A"
        is_today = True
    else:
        label = "WAS A"

    day_name = get_day_of_week(b, day)

    # print the day of the week the date falls on.
    print(f"{month}/{day}/{year} {label} {day_name}.")

    if is_today:
        # nothing to report for today
        end()
        return

    print()

    el_years = year_today - year
    el_months = month_today - month
    el_days = day_today - day

    if el_days < 0:
        el_months = el_months - 1
        el_days = el_days + 30
    if el_months < 0:
        el_years = el_years - 1
        el_months = el_months + 12
    if el_years < 0:
        # target date is in the future
        end()
        return

    if (el_months == 0) and (el_days == 0):
        print("***HAPPY BIRTHDAY***")

    # print report
    print(" " * 23 + "\tYEARS\tMONTHS\tDAYS")
    print(" " * 23 + "\t-----\t------\t----")
    print(f"YOUR AGE (IF BIRTHDATE)\t{el_years}\t{el_months}\t{el_days}")

    life_days = (el_years * 365) + (el_months * 30) + el_days + int(el_months / 2)
    rem_years = el_years
    rem_months = el_months
    rem_days = el_days

    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
        0.35, life_days, rem_years, rem_months, rem_days
    )
    time_report("YOU HAVE SLEPT", used_years, used_months, used_days)
    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
        0.17, life_days, rem_years, rem_months, rem_days
    )
    time_report("YOU HAVE EATEN", used_years, used_months, used_days)

    label = make_occupation_label(rem_years)
    rem_years, rem_months, rem_days, used_years, used_months, used_days = deduct_time(
        0.23, life_days, rem_years, rem_months, rem_days
    )
    time_report(f"YOU HAVE {label}", used_years, used_months, used_days)
    time_report("YOU HAVE RELAXED", rem_years, rem_months, rem_days)

    print()

    # Calculate retirement date
    e = year + 65
    print(" " * 16 + f"***  YOU MAY RETIRE IN {e} ***")
    end()


if __name__ == "__main__":
    main()
